package la.iok.hzsvn.lewin.movie.operation.service;

import la.iok.hzsvn.lewin.movie.core.RoleEnum;
import la.iok.hzsvn.lewin.movie.core.Token;
import la.iok.hzsvn.lewin.movie.core.exception.ErrorCode;
import la.iok.hzsvn.lewin.movie.core.model.UserRoleDetail;
import la.iok.hzsvn.lewin.movie.operation.mapper.ConsumeDetailMapper;
import la.iok.hzsvn.lewin.movie.operation.model.ConsumeDetail;
import la.iok.hzsvn.lewin.movie.services.MovieServiceInvoker;
import la.iok.hzsvn.share.tools.datetime.DateTimeUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class ConsumeDetailServiceImpl implements ConsumeDetailService{
    private final ConsumeDetailMapper mapper;
    private final MovieServiceInvoker movieServiceInvoker;
    private final PlayRecordService playRecordService;
    private final ChargeOrderService chargeOrderService;

    public ConsumeDetailServiceImpl(ConsumeDetailMapper mapper, MovieServiceInvoker movieServiceInvoker,
                                    PlayRecordService playRecordService,
                                    ChargeOrderService chargeOrderService) {
        this.mapper = mapper;
        this.movieServiceInvoker = movieServiceInvoker;
        this.playRecordService = playRecordService;
        this.chargeOrderService = chargeOrderService;
    }

    @Override
    public List<ConsumeDetail> list(Token token, Long orgUnitId, Long roomId, String start, String end) {
        Set<Long> shopOrgUnitIds = new HashSet<>();
        Date s = DateTimeUtil.safelyParseDate(start,"yyyy-MM-dd");
        Date e = DateTimeUtil.safelyParseDate(end,"yyyy-MM-dd");
        if(s != null){
            s = DateTimeUtil.setTime(s,0,0,0,0);
        }
        if(e != null){
            e = DateTimeUtil.setTime(e,23,59,59,999);
        }
        ErrorCode.DATETIME_RANGE_EMPTY_ERROR.assertFalse(s == null || e == null);
        if(token.hasAuthority(RoleEnum.Admin)){
            //全部，只根据参数过滤
            if(orgUnitId != null){
                shopOrgUnitIds.add(orgUnitId);
            }
        }else{
            List<UserRoleDetail> list = movieServiceInvoker.userRoles(token.getUserId());
            UserRoleDetail adminRoles = list.stream().filter(ur->RoleEnum.Admin.name().equals(ur.getRole())).findFirst().orElse(null);
            if(adminRoles != null){
                //用户其实有Admin权限,只是权限所属组织与当前所在组织不匹配，但是Admin权限是不与组织限定的
                //全部,只根据参数过滤
                if(orgUnitId != null){
                    shopOrgUnitIds.add(orgUnitId);
                }
            }else{
                Set<Long> franchisees = new HashSet<>();
                list.forEach(ur->{
                    if(ur.shop()){
                        if(RoleEnum.Manager.name().equals(ur.getRole()) || RoleEnum.ShopManager.name().equals(ur.getRole())){
                            shopOrgUnitIds.add(ur.getOrgUnitId());
                        }
                    }else if(ur.franchisee()){
                        if(RoleEnum.Manager.name().equals(ur.getRole())){
                            franchisees.add(ur.getOrgUnitId());
                        }
                    }
                });
                if(!franchisees.isEmpty()){
                    shopOrgUnitIds.addAll(movieServiceInvoker.childrenOrgUnitIds(franchisees));
                }
                if(orgUnitId != null){
                    //只要指定的店铺数据,那看这个店铺是否在集合中
                    if(shopOrgUnitIds.contains(orgUnitId)){
                        shopOrgUnitIds.clear();
                        shopOrgUnitIds.add(orgUnitId);
                    }else{
                        shopOrgUnitIds.clear();
                    }
                }
                if(shopOrgUnitIds.isEmpty()){
                    return Collections.emptyList();
                }
            }
        }
        return mapper.list(shopOrgUnitIds,roomId,s,e);
    }

    @Override
    public List<ConsumeDetail> exportData(Token token, Long orgUnitId, Long roomId, String start, String end) {
        List<ConsumeDetail> list = list(token,orgUnitId,roomId,start,end);
        list.forEach(d->{
            if(d.getType() == 0){
                //支出应该为负数
                d.setAmount(-d.getAmount());
                d.setPayAmount(-d.getPayAmount());
            }
        });
        return list;
    }

    @Override
    public List<ConsumeDetail> preview(Token token, Long orgUnitId, Long roomId) {
        token.validAnyAuthority(RoleEnum.Admin);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        List<ConsumeDetail> list = list(token,orgUnitId, roomId,"2020-01-01",sdf.format(new Date()));
        Map<Long,Integer> accountBalanceMap = new HashMap<>();
        list.forEach(d->{
            accountBalanceMap.merge(d.getRoomId(),d.getType() == 0?-d.getPayAmount():d.getPayAmount(),Integer::sum);
            d.setAccountRemained(accountBalanceMap.get(d.getRoomId()));
            if(d.getType() == 0){
                //支出应该为负数
                d.setAmount(-d.getAmount());
                d.setPayAmount(-d.getPayAmount());
            }
        });
        return list;
    }

    @Transactional
    @Override
    public List<ConsumeDetail> confirmUpdate(Token token, Long orgUnitId, Long roomId) {
        token.validAnyAuthority(RoleEnum.Admin);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        List<ConsumeDetail> list = list(token,orgUnitId, roomId,"2020-01-01",sdf.format(new Date()));
        Map<Long,Integer> accountBalanceMap = new HashMap<>();
        list.forEach(d->{
            accountBalanceMap.merge(d.getRoomId(),d.getType() == 0?-d.getPayAmount():d.getPayAmount(),Integer::sum);
            if(d.getAccountRemained() == 0){
                d.setAccountRemained(accountBalanceMap.get(d.getRoomId()));
            }
            if(d.getType() == 0){
                playRecordService.update(d.getId(),"accountRemained",d.getAccountRemained());
                //支出应该为负数
                d.setAmount(-d.getAmount());
                d.setPayAmount(-d.getPayAmount());
            }else{
                chargeOrderService.update(d.getId(),"accountRemained",d.getAccountRemained());
            }
        });
        return list;
    }
}
